import os
import PyPDF2
from docx import Document
from io import BytesIO
from typing import Optional, Dict, Any
import re
import json
import requests
import time
import traceback
import socket
from urllib3.util import parse_url

# 大模型 API 配置
API_KEY = "ec7a3689203040939fda2e7f49b20a1e.mxl5BlD9rVNWlh8c"
API_URL = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
MODEL_NAME = "glm-4.5-flash"  # 免费的

def extract_text_from_pdf(file_content: bytes) -> str:
    """从PDF文件中提取文本"""
    try:
        pdf_reader = PyPDF2.PdfReader(BytesIO(file_content))
        text = ""
        for i, page in enumerate(pdf_reader.pages):
            print(f"[DEBUG] 提取PDF第 {i+1} 页文本")
            text += page.extract_text() + "\n"
        print(f"[DEBUG] PDF文本提取完成，总字符数: {len(text)}")
        return text
    except Exception as e:
        print(f"[ERROR] PDF文本提取失败: {str(e)}")
        traceback.print_exc()
        raise Exception(f"PDF文本提取失败: {str(e)}")

def extract_text_from_docx(file_content: bytes) -> str:
    """从Word文档中提取文本，包括段落文本、文本框内容和表格内容"""
    try:
        doc = Document(BytesIO(file_content))
        text = ""
        
        # 提取段落文本（常规文本内容）
        for i, paragraph in enumerate(doc.paragraphs):
            text += paragraph.text + "\n"
        
        # 提取文本框中的文本
        # 文本框内容在Word文档中以特殊的XML结构存储，需要特殊处理
        try:
            # 遍历文档中的所有元素，查找文本框内容
            for elem in doc.element.iter():
                # 查找文本框元素（txbxContent标签）
                if elem.tag.endswith('txbxContent'):
                    # 在文本框中查找所有文本元素
                    for t in elem.iter():
                        # 提取文本内容
                        if t.tag.endswith('t') and hasattr(t, 'text') and t.text:
                            text += t.text + "\n"
        except Exception as shape_error:
            print(f"[DEBUG] 文本框提取过程中的警告: {str(shape_error)}")
        
        # 提取表格中的文本
        for table in doc.tables:
            for row in table.rows:
                for cell in row.cells:
                    text += cell.text + "\n"
        
        print(f"[DEBUG] Word文档文本提取完成，总段落数: {len(doc.paragraphs)}, 总字符数: {len(text)}")
        return text
    except Exception as e:
        print(f"[ERROR] Word文档文本提取失败: {str(e)}")
        traceback.print_exc()
        raise Exception(f"Word文档文本提取失败: {str(e)}")

def extract_text_from_doc(file_content: bytes) -> str:
    """从旧版Word文档(.doc)中提取文本"""
    try:
        # 尝试使用docx库处理，如果失败则抛出异常
        # 对于真正的.doc文件，我们需要使用其他方法
        raise Exception("暂不支持.doc格式文件，请转换为.docx格式")
    except Exception as e:
        print(f"[ERROR] 旧版Word文档(.doc)文本提取失败: {str(e)}")
        # 作为临时解决方案，我们返回一个提示信息
        return "错误：暂不支持.doc格式文件，请转换为.docx格式后再上传。"

def extract_text_from_file(file_content: bytes, filename: str) -> str:
    """根据文件扩展名选择合适的文本提取方法"""
    print(f"[DEBUG] 开始提取文件文本，文件名: {filename}, 大小: {len(file_content)} bytes")
    if filename.lower().endswith('.pdf'):
        result = extract_text_from_pdf(file_content)
        print(f"[DEBUG] PDF文件文本提取完成，字符数: {len(result)}")
        return result
    elif filename.lower().endswith('.docx'):
        result = extract_text_from_docx(file_content)
        print(f"[DEBUG] Word文档(.docx)文本提取完成，字符数: {len(result)}")
        return result
    elif filename.lower().endswith('.doc'):
        # 对于.doc文件，给出明确的错误信息
        print(f"[WARNING] 检测到旧版Word文档(.doc)格式，暂不支持直接解析")
        raise Exception("暂不支持.doc格式文件，请转换为.docx格式后再上传")
    else:
        raise Exception(f"不支持的文件格式: {filename}")

def call_llm_api(prompt: str, max_retries: int = 3) -> Dict[str, Any]:
    """调用大模型API"""
    
    # # 打印提示词
    # if len(prompt) > 0:
    #     start_chars = prompt[:200]
    #     end_chars = prompt[-200:] if len(prompt) > 200 else prompt
    #     print(f"[DEBUG] 提示词前200字符: {repr(start_chars)}")
    #     if len(prompt) > 400:
    #         print(f"[DEBUG] 提示词后200字符: {repr(end_chars)}")
    
    # 解析API URL以获取主机信息
    parsed_url = parse_url(API_URL)
    host = parsed_url.host
    port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80)
    print(f"[DEBUG] API主机信息: {host}:{port}")
    
    try:
        ip_addresses = socket.getaddrinfo(host, port, socket.AF_INET)
        ip_list = [addr[4][0] for addr in ip_addresses]
        print(f"[DEBUG] DNS解析完成，IP地址: {ip_list}")
    except Exception as e:
        print(f"[ERROR] DNS解析失败: {str(e)}")
    
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }
    
    data = {
        "model": MODEL_NAME,
        "messages": [
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.1,  # 降低随机性，使结果更稳定
        "top_p": 0.7,
        "max_tokens": 2048
    }
    
    request_data_size = len(json.dumps(data))
    print(f"[DEBUG] 请求数据大小: {request_data_size} 字符")
    
    # 打印请求数据
    request_data_str = json.dumps(data, ensure_ascii=False)
    if len(request_data_str) > 0:
        start_chars = request_data_str[:300]
        end_chars = request_data_str[-300:] if len(request_data_str) > 300 else request_data_str
        print(f"[DEBUG] 请求数据前300字符: {repr(start_chars)}")
        if len(request_data_str) > 600:
            print(f"[DEBUG] 请求数据后300字符: {repr(end_chars)}")
    
    for attempt in range(max_retries):
        start_time = None
        end_time = None
        try:
            print(f"[DEBUG] 尝试调用大模型API (尝试 {attempt + 1}/{max_retries})")
            start_time = time.time()
            
            try:
                print(f"[DEBUG] 测试与 {host}:{port} 的连接")
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.settimeout(5)
                result = sock.connect_ex((host, port))
                if result == 0:
                    print(f"[DEBUG] 网络连接测试成功")
                else:
                    print(f"[WARNING] 网络连接测试失败，错误码: {result}")
                sock.close()
            except Exception as e:
                print(f"[WARNING] 网络连接测试异常: {str(e)}")
            
            # 发送请求，设置递增超时时间
            timeout = 80 + (attempt * 30)  # 第一次80秒
            print(f"[DEBUG] 发送HTTP请求到 {API_URL}，超时时间: {timeout}秒")
            response = requests.post(
                API_URL, 
                headers=headers, 
                json=data, 
                timeout=timeout,  # 递增超时时间
                verify=True  # 确保SSL验证开启
            )
            end_time = time.time()
            print(f"[DEBUG] API请求完成，耗时: {end_time - start_time:.2f} 秒, 状态码: {response.status_code}")
            
            print(f"[DEBUG] 响应头大小: {len(str(response.headers))} 字符")
            print(f"[DEBUG] 响应内容大小: {len(response.content)} 字符")
            
            # # 打印响应
            # response_text = response.text
            # if len(response_text) > 0:
            #     start_chars = response_text[:300]
            #     end_chars = response_text[-300:] if len(response_text) > 300 else response_text
            #     print(f"[DEBUG] 响应内容前300字符: {repr(start_chars)}")
            #     if len(response_text) > 600: 
            #         print(f"[DEBUG] 响应内容后300字符: {repr(end_chars)}")
            
            # 处理429请求频率限制
            if response.status_code == 429:
                print(f"[WARNING] API调用遇到频率限制 (尝试 {attempt + 1}/{max_retries})")
                if attempt < max_retries - 1:
                    wait_time = (2 ** attempt) * 10 
                    print(f"[DEBUG] 等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                    continue
                else:
                    raise Exception(f"API调用失败，已重试{max_retries}次: 请求频率限制")
            
            # 特别处理500系列错误
            if response.status_code >= 500:
                print(f"[ERROR] API服务器错误 (尝试 {attempt + 1}/{max_retries}): {response.status_code}")
                if attempt < max_retries - 1:
                    wait_time = (2 ** attempt) * 5 
                    print(f"[DEBUG] 等待 {wait_time} 秒后重试...")
                    time.sleep(wait_time)
                    continue
                else:
                    raise Exception(f"API调用失败，已重试{max_retries}次: 服务器错误 {response.status_code}")
            
            response.raise_for_status()
            result = response.json()
            print(f"[DEBUG] API调用成功，响应长度: {len(str(result))} 字符")
            return result
        except requests.exceptions.Timeout as e:
            end_time = time.time()
            if start_time is not None:
                print(f"[ERROR] 超时请求耗时: {end_time - start_time:.2f} 秒")
            else:
                print(f"[ERROR] 请求超时，开始时间未记录")
            print(f"[ERROR] API调用超时 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            if attempt < max_retries - 1:
                wait_time = (2 ** attempt) * 5 
                print(f"[DEBUG] 等待 {wait_time} 秒后重试...")
                time.sleep(wait_time)
            else:
                raise Exception(f"API调用超时，已重试{max_retries}次: {str(e)}")
        except requests.exceptions.ConnectionError as e:
            if start_time is not None:
                end_time = time.time()
                print(f"[ERROR] 连接错误请求耗时: {end_time - start_time:.2f} 秒")
            print(f"[ERROR] API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            if attempt < max_retries - 1:
                wait_time = (2 ** attempt) * 5 
                print(f"[DEBUG] 等待 {wait_time} 秒后重试...")
                time.sleep(wait_time)
            else:
                raise Exception(f"API连接错误，已重试{max_retries}次: {str(e)}")
        except requests.exceptions.RequestException as e:
            if start_time is not None:
                end_time = time.time()
                print(f"[ERROR] 请求异常耗时: {end_time - start_time:.2f} 秒")
            print(f"[ERROR] API调用失败 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            if attempt < max_retries - 1:
                wait_time = (2 ** attempt) * 3 
                print(f"[DEBUG] 等待 {wait_time} 秒后重试...")
                time.sleep(wait_time)
            else:
                raise Exception(f"API调用失败，已重试{max_retries}次: {str(e)}")
        except json.JSONDecodeError as e:
            print(f"[ERROR] API响应解析失败: {str(e)}")
            raise Exception(f"API响应解析失败: {str(e)}")
    
    raise Exception("API调用失败，已达到最大重试次数")

def parse_resume_with_llm(resume_text: str) -> Dict[str, Any]:
    """使用大模型解析简历文本"""

    prompt = f"""
你是一个专业的简历解析器，请从以下简历文本中提取关键信息，并以严格的JSON格式返回结果。

简历文本：
{resume_text}

请提取以下信息并以JSON格式返回，不要包含任何其他内容：
1. year_of_experience: 工作经验年数（数字）（可根据最早工作距今的时间判断）
2. degree: 最高学历（专科/本科/硕士/博士）
3. bachelor_school: 本科学校名称
4. job_type: 职位类型（开发/产品经理/主管/设计）
5. location: 工作城市
6. annual_salary: 年薪（数字，单位为元）（可根据月薪乘12算）

返回格式示例：
{{
  "year_of_experience": 5,
  "degree": "本科",
  "bachelor_school": "清华大学",
  "job_type": "开发",
  "location": "北京",
  "annual_salary": 300000
}}

注意事项：
1. 如果某些信息无法确定，请使用合理的默认值
2. year_of_experience默认值为1
3. degree默认值为"本科"
4. bachelor_school默认值为"其他"
5. job_type默认值为"开发"
6. location默认值为"北京"
7. annual_salary默认值为100000
8. 严格遵守JSON格式，不要添加任何解释或额外文本
"""

    try:
        print(f"[DEBUG] 准备调用大模型API，提示词长度: {len(prompt)} 字符")
        result = call_llm_api(prompt)
        print(f"[DEBUG] 大模型API调用完成")
        
        content = result['choices'][0]['message']['content']
        print(f"[DEBUG] 提取API响应内容，长度: {len(content)} 字符")
        

        try:
            # 首先尝试直接解析
            print("[DEBUG] 尝试直接解析JSON")
            parsed_info = json.loads(content)
        except json.JSONDecodeError:
            print("[DEBUG] 直接解析JSON失败，尝试提取代码块中的JSON")
            json_match = re.search(r'```(?:json)?\s*({.*?})\s*```', content, re.DOTALL)
            if json_match:
                json_str = json_match.group(1)
                print(f"[DEBUG] 提取到代码块中的JSON，长度: {len(json_str)} 字符")
                parsed_info = json.loads(json_str)
            else:
                print("[DEBUG] 未找到代码块，尝试提取大括号中的JSON")
                json_match = re.search(r'({.*?})', content, re.DOTALL)
                if json_match:
                    json_str = json_match.group(1)
                    print(f"[DEBUG] 提取到大括号中的JSON，长度: {len(json_str)} 字符")
                    parsed_info = json.loads(json_str)
                else:
                    raise Exception("无法从API响应中提取有效的JSON")
        
        print("[DEBUG] 验证和清理解析的数据")
        validated_info = {
            "year_of_experience": parsed_info.get("year_of_experience", 1),
            "degree": parsed_info.get("degree", "本科"),
            "bachelor_school": parsed_info.get("bachelor_school", "其他"),
            "job_type": parsed_info.get("job_type", "开发"),
            "location": parsed_info.get("location", "北京"),
            "annual_salary": parsed_info.get("annual_salary", 100000)
        }
        
        # 确保数据类型正确
        try:
            validated_info["year_of_experience"] = float(validated_info["year_of_experience"])
            validated_info["annual_salary"] = float(validated_info["annual_salary"])
        except (ValueError, TypeError):
            validated_info["year_of_experience"] = 1.0
            validated_info["annual_salary"] = 100000.0
            
        valid_degrees = ["专科", "本科", "硕士", "博士"]
        if validated_info["degree"] not in valid_degrees:
            validated_info["degree"] = "本科"
            
        valid_job_types = ["开发", "产品经理", "主管", "设计"]
        if validated_info["job_type"] not in valid_job_types:
            validated_info["job_type"] = "开发"
            
        print(f"[DEBUG] 简历解析完成: {validated_info}")
        return validated_info
        
    except Exception as e:
        print(f"[ERROR] 大模型解析失败: {str(e)}")
        traceback.print_exc()
        # 返回默认值
        return {
            "year_of_experience": 1,
            "degree": "本科",
            "bachelor_school": "其他",
            "job_type": "开发",
            "location": "北京",
            "annual_salary": 100000
        }

def extract_basic_info(text: str) -> Dict[str, Any]:
    """从简历文本中提取基本信息（备用方法）"""
    print(f"[DEBUG] 使用备用方法提取基本信息，文本长度: {len(text)} 字符")
    # 提取工作经验年限（年）
    experience_pattern = r'(\d+)\s*年.*?(工作|经验|从业)'
    experience_match = re.search(experience_pattern, text, re.IGNORECASE)
    year_of_experience = 0
    if experience_match:
        year_of_experience = int(experience_match.group(1))
    
    # 提取学历
    degree_patterns = {
        '博士': r'博士|PhD|Doctor',
        '硕士': r'硕士|Master',
        '本科': r'本科|学士|Bachelor',
        '专科': r'专科|大专|Associate'
    }
    degree = '本科'  # 默认值
    for deg, pattern in degree_patterns.items():
        if re.search(pattern, text, re.IGNORECASE):
            degree = deg
            break
    
    # 提取学校
    school_pattern = r'(清华|北大|浙大|复旦|交大|华科|武大|中山|厦大|南大|中科大|哈工大|西交|电子科大|北航|北理|北邮|北工|北科|北化|北交|华电|北林|北中医|首医|南理工|南航|苏大|南农|中海洋|郑大|西大|云大|贵大|西农|西工大|兰大|东大|吉大|川大|山大|同济|华理|华师|中南|湖大|大连理工|华东师大|厦大|南开|天大|东南|华工|中传|央财|外经贸|贸大|人大|法大|中政|北外|上外|北语|中戏|中传|央美|国美|中音|北体|上体|央音|中戏|北影|中传|央美|国美|中音|北体|上体|央音)'
    school_match = re.search(school_pattern, text)
    bachelor_school = school_match.group(1) if school_match else '其他'
    
    # 提取职位类型
    job_type_patterns = [
        ('产品经理', r'(产品经理|产品总监|产品负责人|产品设计)'),
        ('主管', r'(主管|经理|总监|负责人|Leader|Manager|Director|团队管理)'),
        ('设计', r'(设计师|UI设计|UX设计|用户体验|界面设计|视觉设计)'),
        ('开发', r'(开发|软件|程序|编码|后端|前端|全栈|Java|Python|C\+\+|Go|JavaScript|Node\.js|React|Vue|Angular)')
    ]
    job_type = '开发'  # 默认值
    for jt, pattern in job_type_patterns:
        if re.search(pattern, text, re.IGNORECASE):
            job_type = jt
            break
    
    # 提取工作城市
    city_pattern = r'(北京|上海|广州|深圳|杭州|南京|武汉|成都|西安|苏州|天津|重庆|郑州|青岛|长沙|宁波|无锡|佛山|东莞|大连|沈阳|厦门|昆明|济南|哈尔滨|长春|石家庄|合肥|福州|南昌|南宁|呼和浩特|银川|西宁|兰州|乌鲁木齐|拉萨|海口|三亚|珠海|中山|江门|惠州|汕头|潮州|揭阳|湛江|茂名|肇庆|江门|阳江|云浮|清远|韶关|梅州|河源|汕尾|东莞|中山|潮州|揭阳|湛江|茂名|肇庆|江门|阳江|云浮|清远|韶关|梅州|河源|汕尾)'
    city_match = re.search(city_pattern, text)
    location = city_match.group(1) if city_match else '北京'
    
    # 提取薪资信息
    salary_pattern = r'(\d{4,8})\s*(元|块|K|k)'
    salary_match = re.search(salary_pattern, text, re.IGNORECASE)
    annual_salary = 100000  # 默认
    if salary_match:
        annual_salary = int(salary_match.group(1))
        # 如果是K或k单位，转换为元
        if re.search(r'[Kk]', salary_match.group(0)):
            annual_salary *= 1000
    
    return {
        "year_of_experience": year_of_experience,
        "degree": degree,
        "bachelor_school": bachelor_school,
        "job_type": job_type,
        "location": location,
        "annual_salary": annual_salary
    }

def parse_resume_info(text: str) -> Dict[str, Any]:
    """解析简历文本，提取基本信息
    首先尝试使用大模型API，如果失败则使用正则表达式提取
    """
    try:
        print("[DEBUG] 尝试使用大模型API解析简历")
        result = parse_resume_with_llm(text)
        print("[DEBUG] 大模型API解析完成")
        return result
    except Exception as e:
        print(f"[WARNING] 大模型解析失败，使用备用方法: {str(e)}")
        result = extract_basic_info(text)
        print("[DEBUG] 备用方法解析完成")
        return result
